﻿using System;
using System.Threading;
using System.Windows.Navigation;

namespace Budget.Silver.Core.Locator
{
    public class IocContentLoader : INavigationContentLoader
    {
        private static PageResourceContentLoader DefaultPageContentLoader = new PageResourceContentLoader();

        public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState)
        {
            if (targetUri.ToString().Contains(".xaml"))
                return DefaultPageContentLoader.BeginLoad(targetUri, currentUri, userCallback, asyncState);

            var iar = new IoCNavigationContentAsyncResult(asyncState);
            //Tries to load type from already loaded assemblies
            iar.Result = IoC.Current.Resolve(Type.GetType(GetComponentName(targetUri)));
            userCallback(iar);
            return iar;
        }

        private string GetComponentName(Uri uri)
        {
            return uri.ToString().Split('?')[0];
        }

        public bool CanLoad(Uri targetUri, Uri currentUri)
        {
            if (targetUri.ToString().Contains(".xaml"))
                return DefaultPageContentLoader.CanLoad(targetUri, currentUri);
            // check if the IoC can resolve the object
            return IoC.Current.Kernel.HasComponent(GetComponentName(targetUri));
        }

        public void CancelLoad(IAsyncResult asyncResult)
        {

        }

        public LoadResult EndLoad(IAsyncResult asyncResult)
        {
            if (asyncResult is IoCNavigationContentAsyncResult)
                return new LoadResult((asyncResult as IoCNavigationContentAsyncResult).Result);

            return DefaultPageContentLoader.EndLoad(asyncResult);
        }
    }

    public class IoCNavigationContentAsyncResult : IAsyncResult
    {
        public IoCNavigationContentAsyncResult(object asyncState)
        {
            this.AsyncState = asyncState;
            this.AsyncWaitHandle = new ManualResetEvent(true);
        }

        public object Result { get; set; }

        public object AsyncState { get; private set; }

        public WaitHandle AsyncWaitHandle { get; private set; }

        public bool CompletedSynchronously
        {
            get { return true; }
        }

        public bool IsCompleted
        {
            get { return true; }
        }
    }
}